package com.ruoyi.shop.service.impl;

import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.Date;
import java.util.List;

import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.shop.domain.ShopUserOrder;
import com.ruoyi.shop.service.IShopUserOpenidService;
import com.ruoyi.shop.service.IShopUserOrderService;
import com.ruoyi.shop.util.GenNumberUtils;
import com.ruoyi.shop.util.pay.PayStatus;
import com.ruoyi.shop.util.pay.PaymentRecordConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.shop.mapper.ShopPaymentRecordMapper;
import com.ruoyi.shop.domain.ShopPaymentRecord;
import com.ruoyi.shop.service.IShopPaymentRecordService;
import com.ruoyi.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;

/**
 * 支付记录Service业务层处理
 * 
 * @author Alan Zhang
 * @date 2021-09-14
 */
@Service
public class ShopPaymentRecordServiceImpl implements IShopPaymentRecordService 
{
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private ShopPaymentRecordMapper shopPaymentRecordMapper;
    @Autowired
    private IShopUserOrderService shopUserOrderService;

    /**
     * 查询支付记录
     * 
     * @param id 支付记录主键
     * @return 支付记录
     */
    @Override
    public ShopPaymentRecord selectShopPaymentRecordById(Long id)
    {
        return shopPaymentRecordMapper.selectShopPaymentRecordById(id);
    }

    /**
     * 查询支付记录列表
     * 
     * @param shopPaymentRecord 支付记录
     * @return 支付记录
     */
    @Override
    public List<ShopPaymentRecord> selectShopPaymentRecordList(ShopPaymentRecord shopPaymentRecord)
    {
        return shopPaymentRecordMapper.selectShopPaymentRecordList(shopPaymentRecord);
    }

    /**
     * 新增支付记录
     * 
     * @param shopPaymentRecord 支付记录
     * @return 结果
     */
    @Override
    public int insertShopPaymentRecord(ShopPaymentRecord shopPaymentRecord)
    {
        shopPaymentRecord.setCreateTime(DateUtils.getNowDate());
        return shopPaymentRecordMapper.insertShopPaymentRecord(shopPaymentRecord);
    }

    /**
     * 修改支付记录
     * 
     * @param shopPaymentRecord 支付记录
     * @return 结果
     */
    @Override
    public int updateShopPaymentRecord(ShopPaymentRecord shopPaymentRecord)
    {
        shopPaymentRecord.setUpdateTime(DateUtils.getNowDate());
        return shopPaymentRecordMapper.updateShopPaymentRecord(shopPaymentRecord);
    }

    /**
     * 批量删除支付记录
     * 
     * @param ids 需要删除的支付记录主键
     * @return 结果
     */
    @Override
    public int deleteShopPaymentRecordByIds(String ids)
    {
        return shopPaymentRecordMapper.deleteShopPaymentRecordByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除支付记录信息
     * 
     * @param id 支付记录主键
     * @return 结果
     */
    @Override
    public int deleteShopPaymentRecordById(Long id)
    {
        return shopPaymentRecordMapper.deleteShopPaymentRecordById(id);
    }

    /**
     *  支付记录
     * @param trxNo 交易订单号
     * @return
     */
    @Override
    public ShopPaymentRecord findByTrxNo(String trxNo){
        return shopPaymentRecordMapper.findByTrxNo(trxNo);
    }


    /**
     * 支付前 生成交易记录
     * @param userOrder
     * @param payType
     * @return
     * @throws UnknownHostException
     */
    @Transactional
    @Override
    public ShopPaymentRecord genPayOrder(ShopUserOrder userOrder, String payType) throws UnknownHostException {
        //无法对已经关闭的订单进行支付
        if(userOrder.isClosed()){
            throw new BusinessException("已经关闭的订单。");
        }
        ShopPaymentRecord payment;
        if(userOrder.getPaymentId() == null){
            payment = new ShopPaymentRecord();
        } else {
            payment = selectShopPaymentRecordById(userOrder.getPaymentId());
        }
        payment.setProductTitle(userOrder.getProductTitle());
        payment.setProductRelativeType(userOrder.getProductType());
        payment.setProductRelativeId(userOrder.getId().toString());
        payment.setProductSummary(userOrder.getProductSummary());

        payment.setTrxNo(GenNumberUtils.uuid());
        payment.setTrxType(PaymentRecordConstants.TRX_TYPE_ORDER);
        payment.setTrxNonceStr(GenNumberUtils.uuid());

        payment.setPayerUserId(userOrder.getBuyerId());//预订单用户id一致
        payment.setPayerName(userOrder.getBuyerNickname());
        payment.setPayerFee(BigDecimal.ZERO);
        payment.setPayStatus(PayStatus.UNPAY.getStatus());//预支付

        payment.setPayAmount(userOrder.getOrderRealAmount());
        payment.setPayType(payType);

        //获取ip地址
        InetAddress address = InetAddress.getLocalHost();
        String hostAddress = address.getHostAddress();
        payment.setOrderIp(hostAddress);

        payment.setStatus(PaymentRecordConstants.STATUS_PAY_PRE); //预支付

        //保存 或 更新 payment
        if(payment.getId() == null) {
            insertShopPaymentRecord(payment);
        } else {
            updateShopPaymentRecord(payment);
        }

        //更新 order 的 payment id
        if (userOrder.getPaymentId() == null) {
            userOrder.setPaymentId(payment.getId());
            shopUserOrderService.updateShopUserOrder(userOrder);
        }
        return payment;
    }

    /**
     * 支付成功
     * @param notifyResult 通知结果
     */
    @Transactional
    @Override
    public void paySuccess(WxPayOrderNotifyResult notifyResult) {

        ShopPaymentRecord payment = findByTrxNo(notifyResult.getOutTradeNo());
        if (payment == null) {
            logger.error("{} 订单不存在", notifyResult.getOutTradeNo());
            return;
        }
        // 已经支付成功，重复通知
        if (payment.isPaySuccess()) {
            logger.error("{} 订单已支付", notifyResult.getOutTradeNo());
            return;
        }

        //total_fee 得到的单位是：分
        BigDecimal paySuccessAmount = new BigDecimal(notifyResult.getTotalFee()).divide(BigDecimal.valueOf(100));
        payment.setPaySuccessAmount(paySuccessAmount);

        payment.setPayStatus(PayStatus.SUCCESS_WECHAT.getStatus());
        payment.setPayBankType(notifyResult.getBankType());
        payment.setThirdpartyType("wechat");
        payment.setThirdpartyAppid(notifyResult.getAppid());
        payment.setThirdpartyMchId(notifyResult.getMchId());
        payment.setThirdpartyTradeType(notifyResult.getTradeType());
        payment.setThirdpartyTransactionId(notifyResult.getTransactionId());
        payment.setThirdpartyUserOpenid(notifyResult.getOpenid());

        if (payment.getPaySuccessAmount() == null) {
            payment.setPaySuccessAmount(payment.getPayAmount());
        }
        payment.setStatus(PaymentRecordConstants.STATUS_PAY_SUCCESS);


        Date parse = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, notifyResult.getTimeEnd());
        String format = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, parse);
        Date payTime = new Date();
        try {
            payTime = DateUtils.parseDate(format, DateUtils.YYYY_MM_DD_HH_MM_SS);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        payment.setPayCompleteTime(payTime);
        payment.setPaySuccessTime(payTime);

        if (updateShopPaymentRecord(payment) > 0) {
            shopUserOrderService.paySuccess(payment);
        }


    }

    /**
     * 支付成功
     * @param notifyResult 通知结果
     */
    @Transactional
    @Override
    public void paySuccess(WxPayOrderQueryResult notifyResult) {

        ShopPaymentRecord payment = findByTrxNo(notifyResult.getOutTradeNo());
        if (payment == null) {
            logger.error("{} 订单不存在", notifyResult.getOutTradeNo());
            return;
        }
        // 已经支付成功，重复通知
        if (payment.isPaySuccess()) {
            logger.error("{} 订单已支付", notifyResult.getOutTradeNo());
            return;
        }

        //total_fee 得到的单位是：分
        BigDecimal paySuccessAmount = new BigDecimal(notifyResult.getTotalFee()).divide(BigDecimal.valueOf(100));
        payment.setPaySuccessAmount(paySuccessAmount);

        payment.setPayStatus(PayStatus.SUCCESS_WECHAT.getStatus());
        payment.setPayBankType(notifyResult.getBankType());
        payment.setThirdpartyType("wechat");
        payment.setThirdpartyAppid(notifyResult.getAppid());
        payment.setThirdpartyMchId(notifyResult.getMchId());
        payment.setThirdpartyTradeType(notifyResult.getTradeType());
        payment.setThirdpartyTransactionId(notifyResult.getTransactionId());
        payment.setThirdpartyUserOpenid(notifyResult.getOpenid());

        if (payment.getPaySuccessAmount() == null) {
            payment.setPaySuccessAmount(payment.getPayAmount());
        }
        payment.setStatus(PaymentRecordConstants.STATUS_PAY_SUCCESS);

        Date parse = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, notifyResult.getTimeEnd());
        String format = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, parse);
        Date payTime = new Date();
        try {
            payTime = DateUtils.parseDate(format, DateUtils.YYYY_MM_DD_HH_MM_SS);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        payment.setPayCompleteTime(payTime);
        payment.setPaySuccessTime(payTime);

        if (updateShopPaymentRecord(payment) > 0) {
            shopUserOrderService.paySuccess(payment);
        }
    }


    /**
     * 支付失败
     * @param notifyResult 通知结果
     */
    @Transactional
    @Override
    public AjaxResult payFail(WxPayOrderNotifyResult notifyResult){

        ShopPaymentRecord payment = findByTrxNo(notifyResult.getOutTradeNo());
        if (payment == null) {
            return AjaxResult.error("订单不存在");
        }
        // 已经支付成功，重复通知
        if (payment.isPaySuccess()) {
            return AjaxResult.error("订单已支付");
        }

        shopUserOrderService.payFail(payment);
        return AjaxResult.success();
    }
}
